package cc.rboot._core.helper;

import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * create by RK on 2021/9/15 11:30
 */
public class CollectionCompareHelper {

	private CollectionCompareHelper() {

	}

	/**
	 * 相同类型集合取交集 (左右都有)
	 * @param leftCollection 左集合
	 * @param rightCollection 右集合
	 * @param function 判断数据来源
	 * @param <T> 集合泛型
	 * @param <R> 判断数据来源泛型
	 * @return 两集合的交集
	 */
	public static <T, R> List<T> intersection(Collection<T> leftCollection, Collection<T> rightCollection, Function<T, R> function) {
		return intersection(leftCollection, rightCollection, (a, b) -> Objects.equals(function.apply(a), function.apply(b)));
	}

	/**
	 * 相同类型集合取左集合相对于右集合之间的差集 (左有右没有)
	 * @param leftCollection 左集合
	 * @param rightCollection 右集合
	 * @param function 判断数据来源方法
	 * @param <T> 集合泛型
	 * @param <R> 判断数据来源泛型
	 * @return 左集合相对于右集合之间的差集
	 */
	public static <T, R> List<T> leftDifferent(Collection<T> leftCollection, Collection<T> rightCollection, Function<T, R> function) {
		return leftDifferent(leftCollection, rightCollection, (left, right) -> Objects.equals(function.apply(left), function.apply(right)));
	}

	/**
	 * 不同类型集合取交集，返回集合泛型为A的泛型 (左右都有)
	 * @param leftCollection 左集合
	 * @param rightCollection 右集合
	 * @param lFunction 左集合泛型对象的比较判断数据来源方法
	 * @param rFunction 右集合泛型对象的比较判断数据来源方法
	 * @param <L> 左集合泛型
	 * @param <R> 右集合泛型
	 * @param <C> 比较数据泛型
	 * @return 左集合泛型的交集集合
	 */
	public static <L, R, C> List<L> intersection(Collection<L> leftCollection, Collection<R> rightCollection, Function<L, C> lFunction, Function<R, C> rFunction) {
		return intersection(leftCollection, rightCollection, (a, b) -> Objects.equals(lFunction.apply(a), rFunction.apply(b)));
	}

	/**
	 * 不同类型集合取左集合相对于右集合之间的差集 (左有右没有)
	 * @param leftCollection 左集合
	 * @param rightCollection 右集合
	 * @param lFunction 左集合泛型对象的比较判断数据来源方法
	 * @param rFunction 右集合泛型对象的比较判断数据来源方法
	 * @param <L> 左集合泛型
	 * @param <R> 右集合泛型
	 * @param <C> 比较数据泛型
	 * @return 左集合相比于右差集
	 */
	public static <L, R, C> List<L> leftDifferent(Collection<L> leftCollection, Collection<R> rightCollection, Function<L, C> lFunction, Function<R, C> rFunction) {
		return leftDifferent(leftCollection, rightCollection, (src, compare) -> Objects.equals(lFunction.apply(src), rFunction.apply(compare)));
	}

	/**
	 * 取交集 (左右都有)
	 * @param leftCollection 左集合
	 * @param rightCollection 右集合
	 * @param predicate 断言
	 * @param <L> 左集合泛型
	 * @param <R> 右集合泛型
	 * @return 左集合泛型的交集
	 */
	public static <L, R> List<L> intersection(Collection<L> leftCollection, Collection<R> rightCollection, BiPredicate<L, R> predicate) {
		return leftCollection.stream().filter(left -> {
			for (R right : rightCollection) {
				if (predicate.test(left, right)) {
					return true;
				}
			}
			return false;
		}).collect(Collectors.toList());
	}

	/**
	 * 取左集合差集 (左有右没有)
	 * @param leftCollection 左集合
	 * @param rightCollection 右集合
	 * @param predicate 断言
	 * @param <L> 左集合泛型
	 * @param <R> 右集合泛型
	 * @return 左集合相比于右差集
	 */
	public static <L, R> List<L> leftDifferent(Collection<L> leftCollection, Collection<R> rightCollection, BiPredicate<L, R> predicate) {
		return leftCollection.stream().filter(left -> {
			for (R right : rightCollection) {
				if (predicate.test(left, right)) {
					return false;
				}
			}
			return true;
		}).collect(Collectors.toList());
	}
}
